import { NextRequest } from "next/server";
import { writeFile, mkdir } from "fs/promises";
import { join } from "path";
import mammoth from "mammoth";
import { Document } from "@langchain/core/documents";
import { CharacterTextSplitter } from "langchain/text_splitter";
import { PGVectorStore } from "@langchain/community/vectorstores/pgvector";
import { OllamaEmbeddings } from "@langchain/ollama";
import { embeddingEchart } from '@/db/schema';
import { drizzle } from 'drizzle-orm/node-postgres';
import 'dotenv/config';

export const runtime = "nodejs";

// 初始化数据库连接（用于插入数据）
const db = drizzle(process.env.DATABASE_URL!);

// 提取表格数据
function extractTables(html: string): Array<{ headers: string[]; rows: string[][] }> {
  const tables: Array<{ headers: string[]; rows: string[][] }> = [];
  const tableRegex = /<table[^>]*>([\s\S]*?)<\/table>/gi;
  let match;

  while ((match = tableRegex.exec(html)) !== null) {
    const tableHtml = match[1];
    const rowRegex = /<tr[^>]*>([\s\S]*?)<\/tr>/gi;
    const rows: string[][] = [];
    let rowMatch;

    while ((rowMatch = rowRegex.exec(tableHtml)) !== null) {
      const cellRegex = /<t[dh][^>]*>([\s\S]*?)<\/t[dh]>/gi;
      const cells: string[] = [];
      let cellMatch;

      while ((cellMatch = cellRegex.exec(rowMatch[1])) !== null) {
        // 移除HTML标签，只保留文本
        const text = cellMatch[1]
          .replace(/<[^>]+>/g, "")
          .replace(/&nbsp;/g, " ")
          .trim();
        cells.push(text);
      }

      if (cells.length > 0) {
        rows.push(cells);
      }
    }

    if (rows.length > 0) {
      // 第一行作为表头
      const headers = rows[0];
      const dataRows = rows.slice(1);
      tables.push({ headers, rows: dataRows });
    }
  }

  return tables;
}

// 将表格转换为结构化文本
function formatTableForStorage(
  table: { headers: string[]; rows: string[][] },
  index: number
): string {
  let text = `表格 ${index + 1}:\n`;
  // text += `表头: ${table.headers.join(" | ")}\n`;
  text += `${table.headers.join(" | ")}\n`;
  // text += `数据行:\n`;

  table.rows.forEach((row, rowIndex) => {
    const rowData = row.map((cell, cellIndex) => {
      return `${table.headers[cellIndex] || `列${cellIndex + 1}`}: ${cell}`;
    });
    // text += `  行${rowIndex + 1}: ${rowData.join(", ")}\n`;
    text += `${rowData.join(", ")}\n`;
  });

  return text;
}

export async function POST(req: NextRequest) {
  try {
    const formData = await req.formData();
    const file = formData.get("file") as File;

    if (!file) {
      return Response.json({ ok: false, message: "未上传文件" }, { status: 400 });
    }

    // 保存上传的文件
    const uploadsDir = join(process.cwd(), "uploads");
    await mkdir(uploadsDir, { recursive: true });

    const filePath = join(uploadsDir, file.name);
    const arrayBuffer = await file.arrayBuffer();
    const buffer = Buffer.from(arrayBuffer);
    await writeFile(filePath, buffer);

    // console.log("📄 开始处理Word文档:", file.name);

    // 使用mammoth将Word文档转换为HTML
    const result = await mammoth.convertToHtml({ path: filePath });
    const html = result.value;

    // 提取表格
    const tables = extractTables(html);
    // console.log(`📊 提取到 ${tables.length} 个表格`);

    if (tables.length === 0) {
      return Response.json({
        ok: false,
        message: "文档中未找到表格",
      });
    }

    // 暂时屏蔽向量存储初始化（因为不插入数据库）
    // const store = await initVectorStore();

    // 将表格数据转换为文档（准备存储）
    const documents: Document[] = [];
    tables.forEach((table, index) => {
      const tableText = formatTableForStorage(table, index);
      const tableJson = JSON.stringify({
        headers: table.headers,
        rows: table.rows,
        tableIndex: index,
      });

      documents.push(
        new Document({
          pageContent: tableText,
          metadata: {
            source: file.name,
            type: "table",
            tableIndex: index,
            tableJson: tableJson, // 保存原始JSON数据
            headers: table.headers,
            rowCount: table.rows.length,
          },
        })
      );
    });

    // 使用文本分割器处理长文档
    // 使用换行符作为分隔符，确保按行分割
    const splitter = new CharacterTextSplitter({
      separator: '\n', // 使用换行符分割，这样每行数据会分开
      chunkSize: 55, // 每个块的最大字符数
      chunkOverlap: 5, // 块之间的重叠字符数（参考 InsertPgSql）
      keepSeparator: false,
    });

    const splitDocs = await splitter.splitDocuments(documents);
    // console.log(`📝 分割后得到 ${splitDocs.length} 个文档块`);

    // 检查每个文档的长度，确保不会超过模型限制
    const maxLength = 500; // 设置一个安全的最大长度
    // 确保后续生成向量时不会触发模型长度限制。
    const validDocs = splitDocs.filter((doc) => {
      const length = doc.pageContent.length;
      if (length > maxLength) {
        console.warn(`⚠️  文档块过长 (${length} 字符)，将被跳过: ${doc.pageContent.substring(0, 50)}...`);
        return false;
      }
      return true;
    });

    // console.log(`✅ 有效文档块: ${validDocs.length} 个（已过滤 ${splitDocs.length - validDocs.length} 个过长文档）`);

    // 暂时屏蔽插入向量数据库的代码，防止数据库崩溃
    // 参考 src/index.ts 中的 InsertPgSql 函数实现方式
    // 准备生成向量数据（但不插入）
    // validDocs.slice(0, 3).forEach((doc, index) => {
    //   console.log(`  块${index + 1} (${doc.pageContent.length} 字符): ${doc.pageContent.substring(0, 100)}...`);
    //   console.log(`  元数据:`, doc.metadata);
    // });

    // 生成向量
    const embeddings = new OllamaEmbeddings({
      baseUrl: 'http://192.168.31.159:11434',
      // model: 'qwen:32b', // 使用您想要的模型
      model: 'quentinz/bge-large-zh-v1.5:latest', // 使用您想要的模型
      requestOptions: {
        useMmap: true, // 启用内存映射加载模型
        numThread: 10, // 设置计算使用的线程数
        numGpu: 1, // 设置使用的GPU数量
      },
    });

    const pageContents = validDocs.map((doc) => doc.pageContent);
    // console.log(`🔄 开始生成向量（共 ${pageContents.length} 个文档，总字符数: ${pageContents.reduce((sum, text) => sum + text.length, 0)}）...`);
    
    // 分批处理，避免一次性处理太多数据
    const batchSize = 3; // 每批处理10个文档
    const embeddingsList: number[][] = [];
    
    for (let i = 0; i < pageContents.length; i += batchSize) {
      const batch = pageContents.slice(i, i + batchSize);
      // console.log(`  处理批次 ${Math.floor(i / batchSize) + 1}/${Math.ceil(pageContents.length / batchSize)} (${batch.length} 个文档)...`);
      const batchEmbeddings = await embeddings.embedDocuments(batch);
      embeddingsList.push(...batchEmbeddings);
    }
    // console.log(`✅ 向量生成完成，共 ${embeddingsList.length} 个向量`);

    // 准备插入数据（参考 InsertPgSql 和 main() 中的方式）
    const dataToInsert = validDocs.map((doc, index) => ({
      embedding: embeddingsList[index], // 对应向量数组
      text: doc.pageContent, // 对应 text 字段
      metadata: doc.metadata, // 对应 metadata 字段
    }));

    // console.log(`📊 准备插入的数据结构示例（第1个）:`);
    // console.log(`  向量维度: ${dataToInsert[0].embedding.length}`);
    // console.log(`  文本长度: ${dataToInsert[0].text.length}`);
    // console.log(`  元数据:`, dataToInsert[0].metadata);

    // 使用 drizzle-orm 插入数据到 embeddingEchart 表（参考 main() 中的 db.insert 方式）
    try {
      console.log(`💾 开始插入数据到数据库（共 ${dataToInsert.length} 条）...`);
      await db.insert(embeddingEchart).values(dataToInsert);
      console.log(`✅ 成功插入 ${dataToInsert.length} 条数据到 embeddingEchart 表`);
    } catch (insertError: unknown) {
      const errorMessage = insertError instanceof Error ? insertError.message : String(insertError);
      console.error(`❌ 插入数据库失败:`, errorMessage);
      throw new Error(`插入数据库失败: ${errorMessage}`);
    }

    return Response.json({
      ok: true,
      message: "文档处理成功，数据已插入数据库",
      data: {
        fileName: file.name,
        tableCount: tables.length,
        documentCount: validDocs.length,
        originalDocumentCount: splitDocs.length,
        vectorCount: embeddingsList.length,
        vectorDimension: embeddingsList[0]?.length || 0,
        insertedCount: dataToInsert.length,
      },
    });
  } catch (error: unknown) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    console.error("❌ 处理文档失败:", error);
    return Response.json(
      {
        ok: false,
        message: `处理失败: ${errorMessage}`,
      },
      { status: 500 }
    );
  }
}

